
package com.trade.common.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.trade.common.dao.IGenericDao;
import com.trade.common.util.PaginationSupport;

public class GenericDao<T, ID extends Serializable> extends HibernateDaoSupport
		implements IGenericDao<T, ID> {
	@SuppressWarnings("hiding")
	private Log logger = LogFactory.getLog(getClass());

	protected Class<T> entityClass;

	public GenericDao() {

	}

	@SuppressWarnings("unchecked")
	protected Class<?> getEntityClass() {
		if (entityClass == null) {
			entityClass = (Class<T>) ((ParameterizedType) getClass()
					.getGenericSuperclass()).getActualTypeArguments()[0];
			logger.debug("T class = " + entityClass.getName());
		}
		return entityClass;
	}

	@Override
	public void saveOrUpdate(T t) throws DataAccessException {
		this.getHibernateTemplate().saveOrUpdate(t);
	}

	@Override
	public T load(ID id) throws DataAccessException {
		@SuppressWarnings("unchecked")
		T load = (T) getHibernateTemplate().load(getEntityClass(), id);
		return load;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T get(ID id) throws DataAccessException {
		T load = (T) getHibernateTemplate().get(getEntityClass(), id);
		return load;
	}

	@Override
	public boolean contains(T t) throws DataAccessException {
		return getHibernateTemplate().contains(t);
	}

	@Override
	public void delete(T t, LockMode lockMode) throws DataAccessException {
		getHibernateTemplate().delete(t, lockMode);
	}

	@Override
	public void delete(T t) throws DataAccessException {
		getHibernateTemplate().delete(t);
	}

	@Override
	public void deleteAll(Collection<T> entities) throws DataAccessException {
		getHibernateTemplate().deleteAll(entities);
	}

	@SuppressWarnings({"unchecked", "cast"})
	@Override
	public List<T> find(String queryString, Object value)
			throws DataAccessException {
		List<T> find = (List<T>) getHibernateTemplate()
				.find(queryString, value);
		return find;
	}

	@SuppressWarnings({"unchecked", "cast"})
	@Override
	public List<T> find(String queryString, Object[] values)
			throws DataAccessException {
		List<T> find = (List<T>) getHibernateTemplate().find(queryString,
				values);
		return find;
	}

	@SuppressWarnings({"unchecked", "cast"})
	@Override
	public List<T> find(String queryString) throws DataAccessException {
		return (List<T>) getHibernateTemplate().find(queryString);
	}

	@Override
	public void refresh(T t, LockMode lockMode) throws DataAccessException {
		getHibernateTemplate().refresh(t, lockMode);
	}

	@Override
	public void refresh(T t) throws DataAccessException {
		getHibernateTemplate().refresh(t);
	}

	@Override
	public Serializable save(T t) throws DataAccessException {
		return getHibernateTemplate().save(t);
	}

	@Override
	public void saveOrUpdateAll(Collection<T> entities)
			throws DataAccessException {
		getHibernateTemplate().saveOrUpdateAll(entities);
	}

	@Override
	public void update(T t, LockMode lockMode) throws DataAccessException {
		getHibernateTemplate().update(t, lockMode);
	}

	@Override
	public void update(T t) throws DataAccessException {
		getHibernateTemplate().update(t);
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<T> list() throws DataAccessException {
		return getHibernateTemplate().loadAll(getEntityClass());

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByNamedQuery(String queryName)
			throws DataAccessException {
		return getHibernateTemplate().findByNamedQuery(queryName);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByNamedQuery(String queryName, Object value)
			throws DataAccessException {
		return getHibernateTemplate().findByNamedQuery(queryName, value);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByNamedQuery(String queryName, Object[] values)
			throws DataAccessException {
		return getHibernateTemplate().findByNamedQuery(queryName, values);
	}


	@SuppressWarnings("unchecked")
	@Override
	public T get(String id) throws DataAccessException {
		T load = (T) getHibernateTemplate().get(getEntityClass(), id);
		return load;
	}
	
	@Override
	public void flush(){
		this.getHibernateTemplate().flush();
	}
	
	@Override
	public void clear(){
		this.getHibernateTemplate().clear();
	}

	@Override
	public PaginationSupport findPageByCriteria(
			final DetachedCriteria detachedCriteria, final int pageSize,
			final int startIndex) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)
							throws HibernateException {
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						int totalCount = ((Long) criteria.setProjection(
								Projections.rowCount()).uniqueResult())
								.intValue();
						criteria.setProjection(null);
						List<?> items = criteria.setFirstResult(startIndex)
								.setMaxResults(pageSize).list();
						PaginationSupport ps = new PaginationSupport(items,
								totalCount, pageSize, startIndex);
						return ps;
					}
				}, true);
	}
	
	
	@Override
	public  PaginationSupport findPageByQuery( final  String hql, final String countHql
			,final Object obj,final int pageSize,final int startIndex){ 
	     return (PaginationSupport)getHibernateTemplate().execute( 
	     new  HibernateCallback() { 
	       @Override
		public  Object doInHibernate(Session session)  throws  HibernateException, SQLException { 
	    	   Query query=session.createQuery(countHql);
    		   query.setParameter(0, obj);

	    	   int totalCount=((Long) query.iterate().next()).intValue(); 
	    	   query  =  session.createQuery(hql);
	    	   query.setParameter(0, obj);
	    	   if (pageSize!=-1){
	    		   query.setFirstResult(startIndex); 
	    		   query.setMaxResults(pageSize); 
	    	   }
	           List<?> items  = query.list();
	          PaginationSupport ps = new PaginationSupport(items,
	       totalCount, pageSize, startIndex);
	          return ps;
	             
	             } 
	       },true); 
	  }
	
	public  PaginationSupport findPageByQueryIn( final  String hql, final String countHql
			,final Object obj,final int pageSize,final int startIndex,final String paraName){ 
	     return (PaginationSupport)getHibernateTemplate().execute( 
	     new  HibernateCallback() { 
	    @SuppressWarnings("rawtypes")
		@Override
		public  Object doInHibernate(Session session)  throws  HibernateException, SQLException { 
	    	   Query query=session.createQuery(countHql);
    		   query.setParameterList(paraName, (List)obj);


	    	   int totalCount=((Long) query.iterate().next()).intValue(); 
	    	   query  =  session.createQuery(hql);
	    	   query.setParameterList(paraName, (List)obj);
	    	   if (pageSize!=-1){
	    		   query.setFirstResult(startIndex); 
	    		   query.setMaxResults(pageSize); 
	    	   }
	           List<?> items  = query.list();
	          PaginationSupport ps = new PaginationSupport(items,
	       totalCount, pageSize, startIndex);
	          return ps;
	             
	             } 
	       },true); 
	  }
	
	@Override
	public  PaginationSupport findPageByQuery( final  String hql, final String countHql
			,final Object[] obj,final int pageSize,final int startIndex){ 
	     return (PaginationSupport)getHibernateTemplate().execute( 
	     new  HibernateCallback() { 
	       @Override
		public  Object doInHibernate(Session session)  throws  HibernateException, SQLException { 
	    	   Query query=session.createQuery(countHql);
	    	   if (obj!=null && obj.length>0){
	    		   for (int i=0;i<obj.length;i++){
	    			   
	    			   query.setParameter(i, obj[i]);
	    		   }
	    	   }
	    	   int totalCount=((Long) query.iterate().next()).intValue();
    	  
	    	   query  =  session.createQuery(hql);

	    	   if (obj!=null && obj.length>0){
	    		   for (int i=0;i<obj.length;i++){
	    			   query.setParameter(i, obj[i]);
	    		   }
	    	   }
	    	   if (pageSize!=-1){
	    		   query.setFirstResult(startIndex); 
	    		   query.setMaxResults(pageSize); 
	    	   }
	           List<?> items  = query.list();
	           PaginationSupport ps = null;
	           if (pageSize!=-1){
	        	   ps =new PaginationSupport(items,
	        		       totalCount, pageSize, startIndex);
	           }else{
	        	   ps=new PaginationSupport(items,
	        		       totalCount, totalCount, startIndex);
	           }
	           
	          return ps;
	             
	             } 
	       },true); 
	  }
}
